home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / zap < prev   
Encoding:
Internet Message Format  |  1988-01-31  |  37.6 KB

  1. Subject:  v13i035:  Binary file editor
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Johan Vromans <mcvax!mh.nl!jv>
  7. Posting-number: Volume 13, Issue 35
  8. Archive-name: zap
  9.  
  10. [  This is a simple little editor for binary-type files.  It works under
  11.    Unix, VMS, and MS-DOS.  I'm not sure what "no military use means";
  12.    don't zap the enemy, I guess.  --r$ ]
  13.  
  14.  
  15. Features include -
  16.  
  17.  - looking at the file by byte, word or longword,
  18.  - display contents in octal, hex, decimal and ascii,
  19.  - searching for bytes/words/longwords
  20.  - verification of changes
  21.  - buffered update with optional checksum
  22.  - runs on Unix, VAX/VMS and MS-DOS
  23.  
  24. Zap mimics a program called SIPP (Save Image Patch Program), which
  25. was supplied by Digital Equipment Corp. with the RT-11 operating system.
  26.  
  27. Distribution free as long as you give credit to the original author.
  28. Military use and explicit resale prohibited.
  29.  
  30. Johan Vromans                              | jv@mh.nl via European backbone
  31. Multihouse N.V., Gouda, the Netherlands    | uucp: ..{uunet!}mcvax!mh.nl!jv
  32. "It is better to light a candle than to curse the darkness"
  33.  
  34. #! /bin/sh
  35. # This is a shell archive, meaning:
  36. # 1. Remove everything above the #! /bin/sh line.
  37. # 2. Save the resulting text in a file.
  38. # 3. Execute the file with /bin/sh (not csh) to create:
  39. #    Read.Me
  40. #    zap.c
  41. #    zap.1
  42. #    Makefile
  43. #    mkzap.com
  44. #    mkzap.bat
  45. export PATH; PATH=/bin:/usr/bin:$PATH
  46. if test -f 'Read.Me'
  47. then
  48.     echo shar: "will not over-write existing file 'Read.Me'"
  49. else
  50. cat << \SHAR_EOF > 'Read.Me'
  51. This is zap, a binary file inspector/patcher.
  52.  
  53. Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.
  54. Copyright 1987 Johan Vromans.
  55. Distribution free as long as you give credit to the original author.
  56. Military use and explicit resale prohibited.
  57.  
  58. Features include -
  59.  
  60.  - looking at the file by byte, word or longword,
  61.  - display contents in octal, hex, decimal and ascii,
  62.  - searching for bytes/words/longwords
  63.  - verification of changes
  64.  - buffered update with optional checksum
  65.  - runs on Unix, VAX/VMS and MS-DOS
  66.  
  67. Zap mimics a program called SIPP (Save Image Patch Program), which
  68. was supplied by Digital Equipment Corp. with the RT-11 operating system.
  69.  
  70. ----------------
  71.  
  72. Building zap
  73.  
  74. Zap is pretty portable, mainly because it does not use difficult things.
  75. No shell escapes, no tty rubbish, only standard IO.
  76.  
  77. The only thing which is important to zap is whether your system
  78. has byte ordering like a VAX or not.
  79. When it has its bytes ordered VAX-wise, you may compile zap with -DSWAB=1,
  80. otherwise use -DSWAB=0. If you are not sure: don't specify -DSWAB and zap 
  81. will find out itself.
  82.  
  83. This distribution contains:
  84.  
  85.     Read.Me        this file
  86.     zap.c        C program source
  87.     zap.1        nroff -man manual page
  88.     Makefile    makefile for unix
  89.     mkzap.com    compile for VAX/VMS
  90.     mkzap.bat    compile for MS-DOS
  91.  
  92. ----------------
  93. Special notes for Unix:
  94.  
  95.  - the program has been tested on System V and BSD.
  96.  
  97.  - on swabbing and non-swabbing machines.
  98.  
  99. Special notes for VAX/VMS:
  100.  
  101.  - the program has been tested with VAX-C (not VAX11C).
  102.  
  103.  - always compile with /DEFINE=(SWAB=2) (use the mkzap.com file).
  104.  
  105.  - performs well, but probably limited to stream-lf files.
  106.  
  107. Special notes for MS-DOS:
  108.  
  109.  - the program has been tested with Microsoft C V4 using small model.
  110.  
  111.  - always compile with -DLINT_ARGS.
  112.  
  113. ----------------
  114.  
  115. Suggestions and enhancements are welcome!
  116.  
  117. Johan Vromans, Multihouse Research
  118. Usenet: jv@mh.nl via european backbone mcvax.
  119.  
  120. Disclaimer: Usage of this program is always at your own risk.
  121. SHAR_EOF
  122. if test 1992 -ne "`wc -c < 'Read.Me'`"
  123. then
  124.     echo shar: "error transmitting 'Read.Me'" '(should have been 1992 characters)'
  125. fi
  126. fi
  127. if test -f 'zap.c'
  128. then
  129.     echo shar: "will not over-write existing file 'zap.c'"
  130. else
  131. cat << \SHAR_EOF > 'zap.c'
  132. /* zap.c - program to inspect/patch binary files */
  133.  
  134. static char SCCS_id[] = "@(#)@ zap    1.9    zap.c";
  135.  
  136. static char cprght[] = "\
  137. @(#) Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.\n\
  138. @(#) Copyright 1987 Johan Vromans.\n\
  139. @(#) Distribution free as long as you give credit to the original author.\n\
  140. @(#) Military use and explicit resale prohibited.\n\
  141. @(#) Usage of this program is always at your own risk.";
  142.  
  143. #include <stdio.h>
  144. #include <ctype.h>
  145. #include <signal.h>
  146.  
  147. #ifndef TRUE
  148. #  define TRUE    1
  149. #  define FALSE    0
  150. #endif
  151.  
  152. /* define SWAB=1 for byte swapping machines, such as vax and pdp-11 */
  153. /* otherwise, define it to 0 */
  154. /* if unknown, don't define it (or set it to 2) - zap will find out */
  155. /* when known, it is up to the C compiler to optimize unneeded code */
  156.  
  157. #ifndef SWAB
  158. /* SWAB not defined - use info for machines we know */
  159. # ifdef vax            /* DEC VAX */
  160. #  define SWAB 1
  161. # endif
  162. # ifdef pdp11            /* DEC PDP-11 */
  163. #  define SWAB 1
  164. # endif
  165. # ifdef hp9000s200        /* Hewlett-Packard HP9000/200 (M68xxx) */
  166. #   define SWAB 0
  167. # endif
  168. # ifdef hp9000s500        /* Hewlett-Packard HP9000/500 (FocusII) */
  169. #   define SWAB 0
  170. # endif
  171. # ifdef M_I86            /* Intel 86 family */
  172. #   define SWAB    1 
  173. # endif
  174. #endif
  175.  
  176. #ifdef SWAB
  177. # if SWAB > 1        /* explicitly unknown */
  178. #  undef SWAB
  179. # endif
  180. #endif
  181.  
  182. #ifndef SWAB
  183. int    swab = FALSE;        /* use dynamic method */
  184. #else
  185. #  define swab    SWAB        /* leave it to the compiler to eliminate */
  186. #endif
  187.  
  188. /* About swabbing - 
  189.  *
  190.  *    Representation of data
  191.  *
  192.  *                swabbing    non-swabbing
  193.  *    type        numeric    character    character
  194.  *    byte        0x61    'a'        'a'
  195.  *    word        0x6162    'ba'        'ab'
  196.  *    longword    0x61626364    'dcba'        'abcd'
  197.  */
  198.  
  199. #ifdef MSDOS
  200. # ifdef LINT_ARGS
  201.  
  202. /* function defs as generated by MS-C V4.0 */
  203.  
  204. /*global*/  int main (int, char**);
  205. /*global*/  int decod (char*, long*);
  206. /*global*/  unsigned int gv_file (long);
  207. /*global*/  int locate (long);
  208. /*global*/  int enter (long, int);
  209. /*global*/  int get_value (long);
  210. /*global*/  int put_value (long, long);
  211. /*global*/  int ptv_file (long, char);
  212. /*global*/  int push_loc (long);
  213. /*global*/  long pop_loc (void);
  214. /*global*/  int quit_search (void);
  215. /*global*/  int search (void);
  216. /*global*/  int verify (void);
  217. /*global*/  int gt_line (char*, char*, long, long, char, char*);
  218. /*global*/  int gt_val (char*, long*);
  219. /*global*/  char* pr_val (long, int);
  220. /*global*/  int zap (char*);
  221. /*global*/  int cant (char*);
  222. /*global*/  int remark (char*, long);
  223. /*global*/  int error (char*);
  224. /*global*/  int swabcheck (void);
  225.  
  226. # endif
  227. #endif
  228.  
  229. long    lseek ();
  230. char    *strcpy ();
  231. char    *calloc ();
  232. char    *realloc ();
  233. void    exit();
  234. #define    V_printf    (void) printf
  235. #define    V_fprintf    (void) fprintf
  236. #define    V_sprintf    (void) sprintf
  237. #ifdef lint
  238. void clearerr ();
  239. #endif
  240.  
  241. char    *my_name    = "zap";    /* identification */
  242. char    *usage      = "usage: zap [-cdrsvw] file";
  243.  
  244. /* option flags */
  245.  
  246. int    f_check   = FALSE;    /* request checksum */
  247. int    f_sum     = FALSE;    /* print checksum */
  248. int     f_write   = FALSE;    /* read-write */
  249. int    f_silent  = FALSE;    /* silent */
  250. int    f_batch   = FALSE;    /* running batch mode */
  251. int    f_verbose = FALSE;    /* give more info */
  252.  
  253. /* main routine */
  254.  
  255. main (argc, argv)
  256. int    argc;        /* # arguments + 1 */
  257. char    *argv[];    /* argument pointers */
  258.  
  259.   {
  260.     int        file_cnt;    /* number of files processed */
  261.     char    *arg_ptr;    /* argument pointer */
  262.     char    c;        /* current option character */
  263.  
  264.     swabcheck ();        /* verify or establish swabbing mode */
  265.  
  266.     /* ignore first argument (program name) */
  267.  
  268.     argc--;
  269.     argv++;
  270.  
  271.     f_batch = !isatty (0);
  272.     file_cnt = 0;        /* haven't seen one yet */
  273.  
  274.     while (argc-- > 0)        /* through arguments */
  275.       {
  276.         /* fetch a pointer to the current argument, and
  277.          * increase argv
  278.          */
  279.  
  280.         arg_ptr = *argv;
  281.         argv++;
  282.  
  283.         if (*arg_ptr == '-')        /* must be an option */
  284.           {
  285.             while (c = *++arg_ptr)    /* get option character */
  286.               switch (c)
  287.                 {
  288.  
  289.               case  'C' :
  290.               case  'c' :
  291.                           f_check = TRUE;    /* request checksum */
  292.                           break;
  293.  
  294.               case  'D' :
  295.               case  'd' :
  296.                           f_sum = TRUE;        /* print checksum */
  297.                           break;
  298.  
  299.               case  'R' :
  300.               case  'r' :
  301.                           f_write = FALSE;    /* read-only */
  302.                           break;
  303.  
  304.               case  'S' :
  305.               case  's' :
  306.                           f_silent = TRUE;    /* a little more quiet */
  307.                           break;
  308.  
  309.               case  'V' :
  310.               case  'v' :
  311.               V_printf ("zap version 1.9\n");
  312. #ifndef SWAB
  313.                     if (!f_verbose)
  314.                 remark ("you may recompile with \"-DSWAB=%ld\"",
  315.                   (long)swab);
  316. #endif
  317.                           f_verbose = TRUE;    /* a little less quiet */
  318.                           break;
  319.               case  'W' :
  320.               case  'w' :
  321.                           f_write = TRUE;    /* allow write access */
  322.                           break;
  323.  
  324.               default   : error (usage);
  325.                           break;
  326.                 }
  327.  
  328.             /* this ends the option processing */
  329.           }
  330.         else
  331.           {
  332.             /* it must be a file specification */
  333.  
  334.             file_cnt++;        /* now we've seen one */
  335.  
  336.             zap (arg_ptr);
  337.  
  338.             /* this ends the file processing */
  339.           }
  340.  
  341.         /* this ends the argument processing */
  342.       }
  343.  
  344.     /* if there were no filespecs, give error */
  345.  
  346.     if (!file_cnt)
  347.       error (usage);
  348.  
  349.     /* that's it */
  350.  
  351. #ifdef vaxc
  352.     return (1);
  353. #else
  354.     return (0);
  355. #endif
  356.   }
  357.  
  358. /* current type values. note - value is also size of type */
  359.  
  360. int    cur_type;
  361. #define    BYTE    1
  362. #define WORD    2
  363. #define LWORD    4
  364.  
  365. char dp_type [] = " \\/ |";
  366.  
  367. /* current display mode */
  368.  
  369. int cur_printmode;
  370. #define OCTAL    0
  371. #define DECIMAL    1
  372. #define HEX    2
  373. #define ASCII    3
  374.  
  375. char *defffmt[]    = { "0%05lo", "%6ld", "x%05lx", "0%05lo" };
  376. char *deffmt[]    = { "0%lo", "%ld", "x%lx", "0%lo" };
  377.  
  378. #define BYTEVAL(x)    ((x) & 0xff)
  379.  
  380. /* current file */
  381.  
  382. FILE    *zf;
  383.  
  384. /* get (decimal, hex or octal) value from input line */
  385. /* a zero return value means : ok */
  386.  
  387. int decod (buf, lp)
  388. char    *buf;
  389. long    *lp;
  390.   {
  391.     long    num;
  392.     char    *cp;
  393.     int dooct = FALSE;
  394.     int dohex = FALSE;
  395.     int doasc = FALSE;
  396.  
  397.     num = 0;
  398.     cp = buf;
  399.     if (*cp == ';')        /* select mode */
  400.       {
  401.     cp++;
  402.         if (*cp == 'x' || *cp == 'X')
  403.         dohex = TRUE;
  404.     else
  405.     if (*cp == 'o' || *cp == 'O')
  406.         dooct = TRUE;
  407.     else
  408.     if (*cp == 'd' || *cp == 'D')
  409.       ;
  410.     else
  411.     if (*cp == 'a' || *cp == 'A')
  412.         doasc = TRUE;
  413.     else
  414.       V_printf ("input error");
  415.     cp++;
  416.       }
  417.     else
  418.       {
  419.     while (*cp == '0')
  420.       {
  421.         dooct = TRUE;
  422.         cp++;
  423.       }
  424.     if (*cp == 'x' || *cp == 'X')
  425.       {
  426.         cp++;
  427.         dohex = TRUE;
  428.       }
  429.       }
  430.  
  431.     if (dohex)
  432.       {
  433.     while (isxdigit (*cp))
  434.       {
  435.         num = num * 16 
  436.           + (isdigit (*cp) 
  437.              ? *cp - '0' 
  438.              : (*cp | 0x20) - 'a' + 10);
  439.         cp++;
  440.       }    
  441.       }
  442.     else
  443.     if (dooct)
  444.       {
  445.     while (isdigit (*cp) && *cp < '8')
  446.       {
  447.         num = num * 8 + *cp - '0';
  448.         cp++;
  449.       }    
  450.       }
  451.     else
  452.     if (doasc)
  453.       {
  454.     int i;
  455.     for (i = 0; i < cur_type && *cp; i++)
  456.       {
  457.         if (swab)
  458.         num += ((long)(*cp++)) << (i << 3);
  459.         else
  460.         num = (num << 8) + *cp++;
  461.       }
  462.       }
  463.     else
  464.       {
  465.     while (isdigit (*cp))
  466.       {
  467.         num = num * 10 + *cp - '0';
  468.         cp++;
  469.       }    
  470.       }
  471.  
  472.     *lp = num;
  473.     if (!*cp)
  474.       return (0);
  475.     if (*cp == '^')
  476.       return (-1);    /* special return value for zap */
  477.     else
  478.       return (1);
  479.   }
  480.  
  481. /* retrieve byte from file */
  482.  
  483. unsigned gv_file (addr)
  484. long    addr;
  485.   {
  486.     long    l;
  487.  
  488.     if (fseek (zf, addr, 0))
  489.       remark ("cannot position to %ld", addr);
  490.  
  491.     (void) clearerr (zf);
  492.     l = fgetc (zf);
  493.  
  494.     if (l == EOF)
  495.       remark (ferror(zf) ? "cannot read at %ld" : "read beyond eof", addr);
  496.  
  497.     return (BYTEVAL(l));
  498.   }
  499.  
  500. #define BUF_INC    512
  501. int    tbl_max = BUF_INC;
  502.  
  503. struct ntry
  504.   {
  505.     long    addr;
  506.     char    val;
  507.     char    old;
  508.   }
  509.     *tbl,        /* value table */
  510.     *tbl_cur,        /* last referenced entry in table */
  511.     *tbl_free,        /* next free entry in table */
  512.     *tbl_ptr;        /* work pointer into table */
  513.  
  514. int locate (adr)
  515. long    adr;
  516.   {
  517.     /* lookup address in table. return tbl_cur at correct entry
  518.      * or next higher */
  519.  
  520.     if (tbl_cur >= tbl && tbl_cur < tbl_free && tbl_cur->addr == adr)
  521.       /* just looked up */
  522.       return (TRUE);
  523.  
  524.     for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
  525.       {
  526.         if (tbl_cur->addr > adr)
  527.           break;
  528.         if (tbl_cur->addr == adr)
  529.           return (TRUE);
  530.       }
  531.     return (FALSE);
  532.   }
  533.  
  534. enter (addr, val)
  535. long    addr;
  536. int    val;
  537.   {
  538.     char    old;
  539.  
  540.     /* lookup address */
  541.     if (locate (addr))
  542.       {
  543.         /* store value, if different from file value */
  544.         if (val != tbl_cur->old)
  545.           {
  546.             tbl_cur->val = val;
  547.              return;
  548.           }
  549.         /* else delete entry from table */
  550.         for (tbl_ptr=tbl_cur; tbl_ptr < tbl_free-1; tbl_ptr++)
  551.           tbl_ptr[0] = tbl_ptr[1];
  552.         tbl_free--;
  553.         return;
  554.       }
  555.  
  556.     /* if not found, tbl_cur points at next higher address entry */
  557.     /* insert new entry at appropriate position */
  558.  
  559.     old = gv_file (addr);
  560.     if (val == old)        /* no-op if new == old */
  561.       return;
  562.  
  563.     /* check for space in table, otherwise extend it */
  564.     if (tbl_free == &tbl[tbl_max])
  565.       {
  566.         tbl_max += BUF_INC;
  567.         if ((tbl = (struct ntry*) realloc ((char*) tbl, (unsigned) tbl_max * sizeof (*tbl))) == NULL)
  568.             error ("table overflow");
  569.       }
  570.  
  571.     for (tbl_ptr=tbl_free-1; tbl_ptr >= tbl_cur; tbl_ptr--)
  572.       tbl_ptr[1] = tbl_ptr[0];
  573.  
  574.     tbl_cur->addr = addr;
  575.     tbl_cur->val = val;
  576.     tbl_cur->old = old;
  577.  
  578.     tbl_free++;
  579.   }
  580.  
  581. /* retrieve value from table */
  582.  
  583. int get_value (addr)
  584. long    addr;
  585.   {
  586.     int        val;
  587.  
  588.     if (locate (addr))
  589.       val = tbl_cur->val;
  590.     else
  591.       val = gv_file (addr);
  592.  
  593.     return (val);
  594.   }
  595.  
  596. /* put byte into table */
  597.  
  598. #define put_byte    enter
  599.  
  600. /* put value into table */
  601.  
  602. put_value (addr, val)
  603. long    addr;
  604. long    val;
  605.   {
  606.     int        i;
  607.  
  608.     for (i=0; i<cur_type; i++)
  609.       {
  610.     register long temp = addr + ((swab) ? i : (cur_type-i-1));
  611.         put_byte (temp, (int)BYTEVAL(val));
  612.         val >>= 8;
  613.       }
  614.   }
  615.  
  616. ptv_file (addr, val)
  617. long    addr;
  618. char    val;
  619.   {
  620.     char     c;
  621.  
  622.     c = val;
  623.  
  624.     if (fseek (zf, addr, 0))
  625.       remark ("cannot position to %ld", addr);
  626.  
  627.     (void) clearerr (zf);
  628.     (void) fputc (c, zf);
  629.     if (ferror(zf) || feof(zf))
  630.       remark ("cannot write at %ld", addr);
  631.   }
  632.  
  633. char    buf [132];
  634. char    *pr_val();
  635.  
  636. #define PREV_MAX 256        /* size of previous goto table    */
  637. long    prevs [PREV_MAX];    /* previous goto table        */
  638. int    prevcnt;        /* next free index in previous table */
  639.  
  640. push_loc (loc)
  641. long loc;
  642.   {
  643.     int i;
  644.     if (prevcnt == PREV_MAX)
  645.       {
  646.     for (i=0; i<prevcnt; i++)
  647.       prevs[i] = prevs[i+1];
  648.     prevcnt--;
  649.       }
  650.     prevs[prevcnt++] = loc;
  651.   }
  652.  
  653. long pop_loc ()
  654.   {
  655.     if (prevcnt > 0)
  656.       return (prevs[--prevcnt]);
  657.     return (0);
  658.   }
  659.  
  660. long    last_value;    /* last printed value        */
  661. long    sstart;        /* search starting value    */
  662. long    ennd;        /* search ending value        */
  663. long    interrupted;    /* search was terminated    */
  664. int    diddots;    /* dots were displayed        */
  665.  
  666. int    quit_search ()
  667.   {
  668.     interrupted = sstart;
  669.     sstart = ennd;
  670.   }
  671.  
  672. foundit (addr)
  673. long addr;
  674.   {
  675.     if (diddots)
  676.       V_printf ("\n");
  677.     V_printf ("Found at ");
  678.     V_printf (defffmt[cur_printmode], addr);
  679.     V_printf ("\n");
  680.     diddots = FALSE;
  681.     push_loc (addr);
  682.   }
  683.  
  684. /* search value in file */
  685.  
  686. search ()
  687.   {
  688.     int        bt;        /* first byte thereof    */
  689.     long    first;
  690.     union {
  691.       long ll;
  692.       char ss[4];
  693.     } uu;
  694.  
  695.     if (!gt_val ("Search for ? ", &uu.ll))
  696.       return;
  697.  
  698.     if (!gt_val ("Start at   ? ", &sstart))
  699.       return;
  700.  
  701.     if (!gt_val ("Stop at    ? ", &ennd))
  702.       return;
  703.  
  704.     /* temporary using first to hold EOF value */
  705.     first = lseek (fileno(zf), 0l, 2);
  706.     if (ennd == 0)
  707.       {
  708.     if (f_verbose)
  709.       {
  710.         V_fprintf (stderr, "EOF at ");
  711.         V_fprintf (stderr, deffmt[cur_printmode], first);
  712.         V_fprintf (stderr, "\n");
  713.       }
  714.     ennd = first - cur_type + 1;
  715.       }
  716.  
  717.     if (sstart > ennd)
  718.       {
  719.     remark ("start > end", 0L);
  720.     return;
  721.       }
  722.  
  723.     if (ennd > first)
  724.       {
  725.     if (f_verbose)
  726.       remark ("end > EOF, truncated", 0L);
  727.     ennd = first;
  728.       }
  729.     /* end of using first to hold EOF value */
  730.  
  731. #ifndef SEARCH_ACTUAL
  732.     if (fseek (zf, sstart, 0))
  733.       {
  734.     V_fprintf (stderr, "cannot position to ");
  735.     V_fprintf (stderr, deffmt[cur_printmode], sstart);
  736.     V_fprintf (stderr, "\n");
  737.     return;
  738.       }
  739. #endif
  740.  
  741.     (void) signal (SIGINT, quit_search);
  742.  
  743.     /* shift to align */
  744.     if (!swab)
  745.       {
  746.     if (cur_type == BYTE)
  747.       uu.ss[0] = uu.ss[3];
  748.     else
  749.     if (cur_type == WORD)
  750.       {
  751.         uu.ss[0] = uu.ss[2];
  752.         uu.ss[1] = uu.ss[3];
  753.       }
  754.       }
  755.     bt = BYTEVAL(uu.ss[0]);
  756.  
  757.     first = sstart;
  758.     diddots = interrupted = FALSE;
  759.  
  760.     while (sstart < ennd)
  761.       {
  762.  
  763.     /* print a dot for every 1K processed */
  764.     if (!f_silent && (((first - sstart) & 0x3ff) == 0) && sstart > first)
  765.       {
  766.         V_printf (".");
  767.         (void) fflush (stdout);
  768.         diddots = TRUE;
  769.       }
  770.  
  771. #ifdef SEARCH_ACTUAL
  772.  
  773.     /* searching the actual values (very slow) */
  774.  
  775.         if (get_value (sstart) == bt)
  776.           {
  777.             if (
  778.             ( cur_type == BYTE    /* looking for byte is easy */
  779.             )
  780.              || ( cur_type == WORD    /* word needs another byte */
  781.                    && (get_value (sstart+1L) == BYTEVAL(uu.ss[1]))
  782.                 )
  783.              || ( cur_type == LWORD     /* lword needs three other bytes */
  784.                && (get_value (sstart+1L) == BYTEVAL(uu.ss[1]))
  785.                && (get_value (sstart+2L) == BYTEVAL(uu.ss[2]))
  786.                && (get_value (sstart+3L) == BYTEVAL(uu.ss[3]))
  787.                 )
  788.                )
  789.            foundit (sstart);
  790.           }
  791.     start++;
  792.  
  793. #else
  794.  
  795.     /* searching the old contents of the file */
  796.  
  797.         if (fgetc (zf) == bt)
  798.           {
  799.         int chr;
  800.         if (cur_type == BYTE)    /* looking for byte is easy */
  801.           foundit (sstart);
  802.         else
  803.           {
  804.         chr = fgetc (zf);
  805.         if (chr == BYTEVAL(uu.ss[1]))
  806.           {
  807.             if (cur_type == WORD)
  808.               {
  809.             foundit (sstart);
  810.             ungetc (chr, zf);
  811.               }
  812.             else
  813.               {
  814.             chr = fgetc (zf);
  815.             if (chr == BYTEVAL(uu.ss[2]))
  816.               {
  817.                 chr = fgetc (zf);
  818.                 if (chr == BYTEVAL(uu.ss[3]))
  819.                   foundit (sstart);
  820.               }
  821.             fseek (zf, sstart+1L, 0);
  822.               }
  823.           }
  824.         else
  825.           ungetc (chr, zf);
  826.           }
  827.       }
  828.         sstart++;
  829.     if (ferror (zf) || feof (zf))
  830.       quit_search ();
  831.  
  832. #endif
  833.  
  834.       }                /* while (sstart < ennd) */
  835.  
  836.     if (diddots)
  837.       V_printf ("\n");
  838.     (void) signal (SIGINT, SIG_DFL);
  839.     if (!f_batch && interrupted)
  840.       {
  841.     V_printf ("Interrupted at ");
  842.     V_printf (defffmt[cur_printmode], sstart);
  843.     V_printf ("\n");
  844.       }
  845.   }
  846.  
  847. /* print verification list */
  848.  
  849. verify ()
  850.   {
  851.     long    addr = 0;
  852.  
  853.     /* display all modifications entered until now. display in portions
  854.      * of cur_printmode. align to lower cur_type boundary
  855.      */
  856.     for (tbl_ptr = tbl; tbl_ptr != tbl_free; tbl_ptr++)
  857.     if (tbl_ptr->addr >= addr)
  858.       {
  859.         addr = tbl_ptr->addr & ~(cur_type-1);
  860.         V_printf ("vfy: ");
  861.         V_printf (defffmt[cur_printmode], addr);
  862.         V_printf ("%c %-7s => ", dp_type[cur_type], pr_val (addr, FALSE));
  863.         V_printf ("%-7s\n", pr_val (addr, TRUE));
  864.         addr += cur_type;
  865.       }
  866.   }
  867.  
  868. int gt_line (dst, prompt, arg1, arg2, arg3, arg4)
  869. char    *dst;
  870. char    *prompt;
  871. long    arg1;
  872. long    arg2;
  873. char    arg3;
  874. char    *arg4;
  875.   {
  876.     if (prompt != NULL && !f_silent)
  877.       V_printf (prompt, arg1, arg2, arg3, arg4);
  878.     (void) fflush (stdout);
  879.     if (!gets (dst))
  880.       {
  881.     if (f_batch && !f_silent)
  882.       V_printf ("[eof]\n");
  883. #ifndef vaxc
  884.     (void) putchar ('\n');
  885. #endif
  886.     return (NULL);
  887.       }
  888.     if (f_batch && !f_silent)
  889.       V_printf ("%s\n", dst);
  890.     if (dst[0] == '^' && dst[1] == 'Z' && dst[2] == '\0')
  891.       return (FALSE);
  892.     else
  893.       return (TRUE);
  894.   }
  895.  
  896. int gt_val (prompt, l)
  897. char    *prompt;
  898. long    *l;
  899.   {
  900.     *l = 0l;
  901.     while (gt_line (buf, prompt, 0L, 0L, '\0', NULL))
  902.       {
  903.         if (!decod (buf, l))
  904.           return (TRUE);
  905.       }
  906.     return (FALSE);
  907.   }
  908.       
  909. /* display value, using current settings (result is in static area) */
  910.  
  911. char *pr_val (addr, cur)
  912. long    addr;
  913. int    cur;        /* 1 = use current, 0 = use previous */
  914.   {
  915.     static char dst [64];
  916.     char    *cp;
  917.     long    val;
  918.     int        i;
  919. #   define getbyte(addr)  BYTEVAL((cur) ? get_value (addr) : gv_file (addr))
  920.  
  921.     last_value = 0;
  922.     if (cur_printmode == ASCII)
  923.       {
  924.         cp = dst;
  925.         for (i=0; i<cur_type; i++)
  926.           {
  927.         val = getbyte (addr);
  928.             addr++;
  929.         if (val >= ' ' && val < 0177 && val != '\\')
  930.           *cp++ = val;
  931.         else
  932.           {
  933.         *cp++ = '\\';
  934.         switch ((int)BYTEVAL(val))
  935.           {
  936.         case '\b':    *cp++ = 'b';
  937.                 break;
  938.         case '\n':    *cp++ = 'n';
  939.                 break;
  940.         case '\t':    *cp++ = 't';
  941.                 break;
  942.         case '\f':    *cp++ = 'f';
  943.                 break;
  944.         case '\r':    *cp++ = 'r';
  945.                 break;
  946.         case '\\':    *cp++ = '\\';
  947.                 break;
  948.         default:    V_sprintf (cp, "%o", val);
  949.                 while (*cp) cp++;
  950.                 break;
  951.           }
  952.           }
  953.         *cp++ = ' ';
  954.       }
  955.     *cp = '\0';
  956.       }
  957.     else
  958.       {
  959.     val = 0l;
  960.     switch (cur_type)
  961.       {
  962.     case BYTE:
  963.             val = getbyte (addr);
  964.         break;
  965.         case WORD:
  966.         if (swab) {
  967.           val =              getbyte (addr+1L);
  968.           val = (val << 8) | getbyte (addr  );
  969.         }
  970.         else {
  971.           val =              getbyte (addr  );
  972.           val = (val << 8) | getbyte (addr+1L);
  973.         }
  974.         break;
  975.     case LWORD:
  976.         if (swab) {
  977.           val =              getbyte (addr+3L);
  978.           val = (val << 8) | getbyte (addr+2L);
  979.           val = (val << 8) | getbyte (addr+1L);
  980.           val = (val << 8) | getbyte (addr  );
  981.         }
  982.         else {
  983.           val =              getbyte (addr  );
  984.           val = (val << 8) | getbyte (addr+1L);
  985.           val = (val << 8) | getbyte (addr+2L);
  986.           val = (val << 8) | getbyte (addr+3L);
  987.         }
  988.             break;
  989.       }
  990.     if ((last_value = val) != 0 || cur_printmode != OCTAL)
  991.       V_sprintf (dst, deffmt[cur_printmode], val);
  992.     else
  993.       (void) strcpy (dst, "0");
  994.       }
  995.  
  996.     return (dst);
  997.   }
  998.  
  999. zap (fname)
  1000. char    *fname;
  1001.  
  1002.   {
  1003.     long    base;            /* base of patching sequence    */
  1004.     long    offset;            /* offset from base        */
  1005.     long    val;            /* holding variable for values    */
  1006.     int        i;            /* scratch            */
  1007.     char    chr;            /* scratch            */
  1008.     int        check;            /* checksum value        */
  1009.     int        need_head;        /* header toggle        */
  1010.     int        checkwrite = TRUE;    /* check for write access    */
  1011.     int        goon = TRUE;        /* until ^Y is used */
  1012.     static char *fmt [] = {
  1013.                 "0%05lo  0%05lo%c %-7s ",
  1014.                 "%6ld  %6ld%c %-7s ",
  1015.                 "x%05ld  x%05lx%c %-7s ",
  1016.                 "0%05lo  0%05lo%c %-7s " };
  1017.  
  1018.     /* open file */
  1019.  
  1020. #ifdef MSDOS
  1021.     if ((zf = fopen (fname, (f_write) ? "rb+" : "rb")) == NULL)
  1022. #else
  1023.     if ((zf = fopen (fname, (f_write) ? "r+" : "r")) == NULL)
  1024. #endif
  1025.       cant (fname);
  1026.  
  1027.     /* set defaults and allocate table */
  1028.  
  1029.     cur_type = BYTE;
  1030.     cur_printmode = OCTAL;
  1031.     if (!tbl)
  1032.       tbl = (struct ntry*) calloc ((unsigned)tbl_max, sizeof (struct ntry));
  1033.     if (!tbl)
  1034.       error ("no room for table");
  1035.     tbl_cur = tbl_free = tbl;
  1036.     prevcnt = 0;        /* reset previous location table */
  1037.  
  1038.     /* loop 1 : loop on Base values */
  1039.  
  1040.     while (goon && gt_val ("Base ?    ", &base))
  1041.       {
  1042.         /* loop 2 : loop on offset values */
  1043.  
  1044.         while (goon && gt_val ("Offset ?  ", &offset))
  1045.           {
  1046.             need_head = TRUE;
  1047.  
  1048.             /* loop 3 : loop on patch commands */
  1049.  
  1050.             while (goon)
  1051.               {
  1052.                 if (need_head && !f_silent)
  1053.                   V_printf ("Base    Offset  Value   New\n");
  1054.             need_head = FALSE;
  1055.  
  1056.                 if (!gt_line (buf, fmt[cur_printmode], base, offset,
  1057.                       dp_type[cur_type], pr_val (base+offset, TRUE)))
  1058.                   break;
  1059.  
  1060.                 switch (buf[0])
  1061.                   {
  1062.             case '\0':
  1063.                 /* close current, advance and open new location */
  1064.                        offset += cur_type;
  1065.                 break;
  1066.             case '/':
  1067.                 /* re-open current using new type */
  1068.                 cur_type = WORD;
  1069.                 break;
  1070.                 case '\\':
  1071.                 /* re-open current using new type */
  1072.                 cur_type = BYTE;
  1073.                 break;
  1074.             case '|':
  1075.                 /* re-open current using new type */
  1076.                 cur_type = LWORD;
  1077.                 break;
  1078.             case '^':
  1079.             if (buf[1] == '\0')
  1080.               {
  1081.                 /* close current, backup and open new location */
  1082.                 offset -= cur_type;
  1083.                 break;
  1084.               }
  1085.             if (buf[1] != 'Y' || buf[2] != '\0')
  1086.               break;
  1087.             /* FALL THROUGH */
  1088.         case '\031':    /* ^Y */
  1089.             goon = FALSE;
  1090.             break;
  1091.                 case '>':
  1092.                         /* goto new location */
  1093.                         if (!decod (&buf[1], &val))
  1094.                           {
  1095.                 push_loc (base+offset);
  1096.                             offset = buf[1] ? val : last_value;
  1097.                           }
  1098.                         break;
  1099.                 case '<':
  1100.                         /* goto location */
  1101.                         if (buf[1] == '\0' && prevcnt > 0)
  1102.               offset = pop_loc () - base;
  1103.                         break;
  1104.             case ';':
  1105.                 /* change current display mode ... */
  1106.                         chr = buf[1];
  1107.                 if (isupper (chr))
  1108.                           chr = tolower (chr);
  1109.                 if (chr == 'o')
  1110.                           cur_printmode = OCTAL;
  1111.                 else
  1112.                 if (chr == 'd')
  1113.                           cur_printmode = DECIMAL;
  1114.                 else
  1115.                 if (chr == 'x')
  1116.                           cur_printmode = HEX;
  1117.                 else
  1118.                 /* ... or store ascii bytes ... */
  1119.                 if (chr == 'a')
  1120.                           {
  1121.                             cur_printmode = ASCII;
  1122.                             for (i=2; chr=buf[i]; i++)
  1123.                               {
  1124.                 if (checkwrite && !f_write)
  1125.                   {
  1126.                     need_head = TRUE;
  1127.                     checkwrite = FALSE;
  1128.                     remark ("no write access", 0L);
  1129.                   }
  1130.                                 put_byte (base+offset, chr);
  1131.                                 offset++;
  1132.                               }
  1133.                           }
  1134.                 else
  1135.                 /* ... or print modifications ... */
  1136.                 if (chr == 'v')
  1137.                   {
  1138.                             verify ();
  1139.                             need_head = TRUE;
  1140.                           }
  1141.                         else
  1142.                 /* ... or search values */
  1143.                         if (chr == 's')
  1144.                           {
  1145.                             search ();
  1146.                             need_head = TRUE;
  1147.                           }
  1148.  
  1149.                 break;
  1150.                 default:
  1151.                 if ((i = decod (buf, &val)) <= 0)
  1152.                   {
  1153.                 if (checkwrite && !f_write)
  1154.                   {
  1155.                 need_head = TRUE;
  1156.                 checkwrite = FALSE;
  1157.                 remark ("no write access", 0L);
  1158.                   }
  1159.                     put_value (base+offset, val);
  1160.                     if (!i)
  1161.                       offset += cur_type;
  1162.                     else
  1163.                               offset -= cur_type;
  1164.                   }
  1165.                   }
  1166.             /* loop on patch commands */
  1167.               }
  1168.             /* loop on offset values */
  1169.           }
  1170.         /* loop on base values */
  1171.       }
  1172.  
  1173.     /* compute checksum, if requested */
  1174.  
  1175.     if (f_check || f_sum)
  1176.       {
  1177.         check = 0;
  1178.         for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
  1179.           check ^= (BYTEVAL(tbl_cur->val) | ((tbl_cur->old << 8) & 0xff00));
  1180.         if (f_sum)
  1181.       {
  1182.         V_printf ("Checksum = ");
  1183.         V_printf (deffmt[cur_printmode], check);
  1184.         V_printf ("\n");
  1185.       }
  1186.       }
  1187.  
  1188.     /* apply patches, after checksum verification */
  1189.  
  1190.     tbl_cur = tbl;
  1191.  
  1192.     if (f_write)
  1193.       {
  1194.         /* verify checksum */
  1195.  
  1196.         if (f_check)
  1197.           while (gt_val ("Checksum ? ", &val))
  1198.             if (val == check || f_batch)
  1199.               break;
  1200.  
  1201.         if (!(f_check && val != check))
  1202.           for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
  1203.                ptv_file (tbl_cur->addr, tbl_cur->val);
  1204.       }
  1205.     
  1206.     if (tbl_cur != tbl_free)
  1207.       error ("no modifications made");
  1208.  
  1209.     if (!f_silent && f_write && tbl == tbl_free)
  1210.       remark ("no modifications requested", 0L);
  1211.  
  1212.     /* close file and exit */
  1213.  
  1214.     (void) fclose (zf);
  1215.   }
  1216.  
  1217. cant (s)
  1218. char *s;
  1219.   {
  1220.     V_fprintf (stderr, "%s: cannot open %s\n", my_name, s);
  1221.     exit (1);
  1222.   }
  1223.  
  1224. remark (s, a)
  1225. char *s;
  1226. long a;
  1227.   {
  1228.     V_fprintf (stderr, "%s: ", my_name);
  1229.     V_fprintf (stderr, s, a);
  1230.     V_fprintf (stderr, "\n");
  1231.   }
  1232.  
  1233. error (s)
  1234. char *s;
  1235.   {
  1236.     V_fprintf (stderr, "%s: %s\n", my_name, s);
  1237.     exit (1);
  1238.   }
  1239.  
  1240. swabcheck ()
  1241.   {
  1242.     union {
  1243.       short s;
  1244.       char a[2];
  1245.     } u;
  1246.     u.s = 0x1357;
  1247. #ifdef SWAB
  1248. #if SWAB
  1249.     if (!(u.a[0] == 0x57 && u.a[1] == 0x13))
  1250.       error ("please recompile with \"-DSWAB=0\"");
  1251. #else
  1252.     if (!(u.a[0] == 0x13 && u.a[1] == 0x57))
  1253.       error ("please recompile with \"-DSWAB=1\"");
  1254. #endif
  1255. #else
  1256.     swab = (u.a[0] == 0x57 && u.a[1] == 0x13);
  1257. #endif
  1258. #ifdef lint
  1259.     SCCS_id[0] = cprght[0] = '\0';
  1260. #endif
  1261.   }
  1262. SHAR_EOF
  1263. if test 24693 -ne "`wc -c < 'zap.c'`"
  1264. then
  1265.     echo shar: "error transmitting 'zap.c'" '(should have been 24693 characters)'
  1266. fi
  1267. fi
  1268. if test -f 'zap.1'
  1269. then
  1270.     echo shar: "will not over-write existing file 'zap.1'"
  1271. else
  1272. cat << \SHAR_EOF > 'zap.1'
  1273. .TH ZAP 1
  1274. .ad b
  1275. .SH NAME
  1276. zap \- binary inspect or modify files
  1277. .PP
  1278. .SH SYNOPSIS
  1279. .PP
  1280. .B zap
  1281. .\" single character options
  1282. .RB [ \-cdrsvw ]
  1283. .\" options with a value
  1284. .\" name arguments
  1285. file
  1286. .SH VERSION INFO
  1287. .PP
  1288. @(#)@ ZAP 1.9 - 87/11/04
  1289. .br
  1290. Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.
  1291. .br
  1292. Copyright 1987 Johan Vromans.
  1293. .br
  1294. Distribution free as long as you give credit to the original author.
  1295. .br
  1296. .Military use and explicit resale prohibited.
  1297. .br
  1298. Usage of this program is always at your own risk.
  1299. .SH DESCRIPTION
  1300. .PP
  1301. .I Zap\^
  1302. can be used to inspect and/or modify files. It regards the file as a
  1303. sequence of bytes, words (2 bytes) or longwords (4 bytes). Changes are
  1304. buffered, and only applied to the file upon normal completion. Only
  1305. real changes are considered a modification, e.g. a change of 1 to 1 is
  1306. a no-operation, and a change of 1 to 2 and then again to 1 discards
  1307. the modification.
  1308. .PP
  1309. Input may be redirected from a file for batch-mode patching.
  1310. .PP
  1311. .I Zap\^
  1312. regards locations in a file to be an 
  1313. .I offset
  1314. to a 
  1315. .IR base .
  1316. After invokation, 
  1317. .I zap
  1318. asks for the base value. When end-of-file is issued, the program
  1319. terminates. After the base value has been entered, 
  1320. .I zap
  1321. asks for the offset value. End-of-file makes it go back to the "Base"
  1322. prompt. After the offset value is entered,
  1323. .I zap
  1324. displays 
  1325. the offset, base and contents of the current location, and
  1326. waits for commands to execute. 
  1327. Typing end-of-file to the command prompt makes
  1328. .I zap
  1329. go back to the "Offset" question.
  1330. .PP
  1331. .I Zap
  1332. operates in one of three modes: byte, word or longword. Words and
  1333. longwords need not be aligned. The current mode is identified by a 
  1334. "\e" for byte, "/" for word and "|" for longword mode.
  1335. .br
  1336. The contents of a location are displayed in one of four formats: octal,
  1337. decimal, hexadecimal or ascii. See the commands how to change this format.
  1338. In ascii format, some interpretation is made to show special control
  1339. characters.
  1340. .PP
  1341. An example of 
  1342. .IR zap 's
  1343. output (user input in bold):
  1344. .sp
  1345. .in +.5i
  1346. .nf
  1347. Base ?    \fB0100\fP
  1348. Offset ?  \fB0200\fP
  1349. Base    Offset  Value   New
  1350. 000100  000200\e 0130    \fB/\fP
  1351. 000100  000200/ 054117  
  1352. 000100  000202/ 045200  
  1353. 000100  000204/ 063004  \fB^Z\fP
  1354. Offset ?  \fB^Z\fP
  1355. Base ?    \fB^Z\fP
  1356. .in
  1357. .fi
  1358. .PP
  1359. Each command is terminated by a <newline>. Valid commands are:
  1360. .PP
  1361. .I
  1362. Changing mode
  1363. .sp
  1364. .TP 7
  1365. .B \e
  1366. change to byte mode.
  1367. .TP
  1368. .B /
  1369. change to word (2-byte) mode.
  1370. .TP
  1371. .B |
  1372. change to longword (4-byte) mode.
  1373. .PP
  1374. .I
  1375. Changing display format
  1376. .TP 7
  1377. .B ;a
  1378. change display format to ascii.
  1379. In ascii format, the base and offset values are displayed in octal.
  1380. .TP
  1381. .B ;d
  1382. change display format to decimal.
  1383. .TP
  1384. .B ;o
  1385. change display format to octal.
  1386. .TP
  1387. .B ;x
  1388. change display format to hexadecimal.
  1389. .PP
  1390. .I
  1391. Moving around
  1392. .TP 7
  1393. <empty>
  1394. an empty line advances to the next location.
  1395. .TP
  1396. .B ^
  1397. a caret backs up to the previous location.
  1398. .TP
  1399. .BI > nnn
  1400. moves 
  1401. .I offset
  1402. to the specified location. If
  1403. .I nnn
  1404. is omited, the contents of the current location are used.
  1405. The current location is saved in the location table.
  1406. Up to 256 saved locations can be restored in a last-in
  1407. first-out manner. 
  1408. .TP
  1409. .B <
  1410. move back to the most recently saved location.
  1411. .PP
  1412. .I
  1413. Modifying contents
  1414. .TP 7
  1415. .I nnn
  1416. the contents of the current location are set to 
  1417. .IR nnn .
  1418. This can be an octal, decimal or a hexadecimal number in the form
  1419. .I nnn
  1420. (decimal),
  1421. .BI 0 nnn
  1422. (octal),
  1423. .BI 0x nnn
  1424. (hex).
  1425. The offset is advanced to the next location.
  1426. .TP
  1427. .IB nnn ^
  1428. the contents of the current location are set to 
  1429. .I nnn
  1430. as described above.
  1431. The offset is backed up to the previous location.
  1432. .TP
  1433. .BI ;a abc
  1434. change display format to ascii, and store the ascii characters
  1435. .I abc
  1436. starting from the current location. Any number of caracters can be
  1437. stored this way. The current offset is advanced to the next location.
  1438. .PP
  1439. .I
  1440. Miscellaneous commands
  1441. .TP 7
  1442. .B ;v
  1443. verify - prints a list of pending modifications. 
  1444. .TP
  1445. .B ;s
  1446. search - asks for a search value and boundaries, and then searches
  1447. for the specfied value. The locations where it is found are printed, and
  1448. also stored in the location table.
  1449. .br
  1450. The search applies to the file contents only, any pending modifications are
  1451. ignored during the search.
  1452. .br
  1453. The argument to the search can be supplied numerically (decimal, octal or
  1454. hex), or in the format
  1455. .BI ;a pqr
  1456. which causes it to be interpreted as an ascii search argument. The number
  1457. of characters allowed depends on the current mode of operation: 1 for byte
  1458. mode, 2 for word mode, and 4 for longword mode.
  1459. .br
  1460. A search can be interrupted using the terminal interrupt signal.
  1461. Note that the current mode controls the search. If zap is in byte mode, the
  1462. search is for a byte, and so on. When searching for words or longwords,
  1463. word boundaries are ignored.
  1464. .br
  1465. During the search, a "." is displayed for each 1024 bytes processed. This
  1466. can be suppressed with the 
  1467. .B \-s
  1468. command line option.
  1469. .TP
  1470. .B ^Y
  1471. (caret-uppercase-Z or control/Y) terminates the 
  1472. .I zap
  1473. loop without asking for new offset/base values.
  1474. .TP
  1475. .B ^Z
  1476. (caret-uppercase-Z) can be used as end-of-file signal. It's main use is in
  1477. batch files.
  1478. .PP
  1479. The following options may be given (in any order)
  1480. before the file-name argument:
  1481. .PP
  1482. .TP 7
  1483. .B \-c
  1484. calculates a 16-bit checksum involving all modifications. The order in
  1485. which the modifications are made is not important. 
  1486. .I Zap
  1487. requests a checksum value to be entered upon completion, and
  1488. requires this value to match the checksum. If they differ, no
  1489. modifications are made.
  1490. .TP
  1491. .B \-d
  1492. calculates the checksum and print its value upon completion.
  1493. .TP
  1494. .B \-r
  1495. access the 
  1496. .I file
  1497. for inspection only. This is the default.
  1498. .TP
  1499. .B \-s
  1500. work silently. No prompts and remarks are displayed. This can be used
  1501. for batch-like processing, if input has been re-directed from a file.
  1502. .TP
  1503. .B \-v
  1504. Supply informational messages.
  1505. .TP
  1506. .B \-w
  1507. access the
  1508. .I file
  1509. in a mode which allows modification.
  1510. .SH DIAGNOSTICS
  1511. .TP 7
  1512. no write access
  1513. a modification is made, and the
  1514. .B \-w
  1515. option was not supplied. This message is showed only once.
  1516. .TP
  1517. no modifications made
  1518. the file has not been modified, either because the
  1519. .B \-w
  1520. option was missing, or the requested checksum did not match.
  1521. This situation is considered an error.
  1522. .TP
  1523. no modifications requested
  1524. the file was accessed using the
  1525. .B \-w
  1526. option, but no changes were pending. This is an informational message.
  1527. .TP
  1528. input error
  1529. an invalid input format was supplied to a numeric prompt. The question is
  1530. repeated.
  1531. .TP
  1532. start > end
  1533. (warning) the end value for a search exceeded the starting position. The
  1534. search is not executed.
  1535. .TP
  1536. EOF > end, truncated
  1537. (warning) the end value for a search exceeded the end-of-file. The end-of-file value
  1538. is used.
  1539. .TP
  1540. you may recompile with "-DSWAB=\fIX\fP"
  1541. (informational)
  1542. .I zap\^
  1543. found out that your system swabs bytes (\fIX\fP = 1) or not (\fX\fP = 0).
  1544. You may use this in a subsequent compilation.
  1545. .TP
  1546. please recompile with "-DSWAB=\fIX\fP"
  1547. (fatal)
  1548. .I zap\^
  1549. found out that your system swabs bytes (\fIX\fP = 1) or not (\fX\fP = 0),
  1550. but the opposite was specified during compilation. You will have to
  1551. recompile with the correct value.
  1552. .PP
  1553. messages from reading/writing/positioning the file.
  1554. .SH BUGS
  1555. .PP
  1556. Usage of this program is at your own risk. Use 
  1557. .IR cmp (1)
  1558. to verify any changes.
  1559. .SH AUTHORS
  1560. .PP
  1561. Johan Vromans - Multihouse Research.
  1562. .sp
  1563. USENET: jv@mh.nl via european backbone mcvax.
  1564. .PP
  1565. There may be some resemblance with an RT-11 program called SIPP.
  1566. SHAR_EOF
  1567. if test 7418 -ne "`wc -c < 'zap.1'`"
  1568. then
  1569.     echo shar: "error transmitting 'zap.1'" '(should have been 7418 characters)'
  1570. fi
  1571. fi
  1572. if test -f 'Makefile'
  1573. then
  1574.     echo shar: "will not over-write existing file 'Makefile'"
  1575. else
  1576. cat << \SHAR_EOF > 'Makefile'
  1577. # Makefile for zap
  1578.  
  1579. # Define SWAB to 1 if your machine swabs bytes, like a vax, otherwise use
  1580. # the value 0.
  1581. # A number of systems types are already known to zap, like vax, pdp11
  1582. # and intel processors.
  1583. # If you do this wrong, zap will abort with an appropriate message.
  1584. # Define SWAB=2 if you want to force zap to find out itself, running
  1585. # 'zap -i' will give you advise.
  1586.  
  1587. #SWAB    =        # unknown (uses built-ins if possible, or find out)
  1588. #SWAB    = -DSWAB=0    # normal system
  1589. #SWAB    = -DSWAB=1    # vax
  1590. #SWAB    = -DSWAB=2    # unknown (overrides built-ins)
  1591.  
  1592. CFLAGS    = -O -s
  1593.  
  1594. zap:    zap.c
  1595.     $(CC) $(CFLAGS) $(SWAB) zap.c -o zap
  1596.  
  1597. # change these for your site
  1598.  
  1599. DESTDIR    = /usr/local/bin
  1600. DSTOWN    = bin
  1601. DSTGRP    = bin
  1602. MANDIR    = /usr/local/man/man1
  1603.  
  1604. install: zap
  1605.     cp zap $(DESTDIR)/zap
  1606.     chmod 0755 $(DESTDIR)/zap
  1607.     chgrp $(DSTGRP) $(DESTDIR)/zap
  1608.     chown $(DSTOWN) $(DESTDIR)/zap
  1609.     cp zap.1 $(MANDIR)/zap.1
  1610.     chmod 0644 $(MANDIR)/zap.1
  1611.     chgrp $(DSTGRP) $(MANDIR)/zap.1
  1612.     chown $(DSTOWN) $(MANDIR)/zap.1
  1613.  
  1614. SOURCES    = Read.Me zap.c zap.1 Makefile mkzap.com mkzap.bat
  1615. SHAR    = zap.shar
  1616.  
  1617. zap.shar:
  1618.     shar -c $(SOURCES) > $(SHAR)
  1619.  
  1620. clean:
  1621.     rm -f $(SOURCES) $(SHAR) zap zap.o a.out core
  1622. SHAR_EOF
  1623. if test 1137 -ne "`wc -c < 'Makefile'`"
  1624. then
  1625.     echo shar: "error transmitting 'Makefile'" '(should have been 1137 characters)'
  1626. fi
  1627. fi
  1628. if test -f 'mkzap.com'
  1629. then
  1630.     echo shar: "will not over-write existing file 'mkzap.com'"
  1631. else
  1632. cat << \SHAR_EOF > 'mkzap.com'
  1633. $! compile & link zap for VAX/VMS
  1634. $!
  1635. $ cc /define=(SWAB=2) zap.c
  1636. $ link zap,sys$library:vaxcrtl/lib
  1637. $!
  1638. $! invoke by symbol
  1639. $!
  1640. $ zap :== $'f$environment("default")'zap.exe
  1641. $!
  1642. SHAR_EOF
  1643. if test 174 -ne "`wc -c < 'mkzap.com'`"
  1644. then
  1645.     echo shar: "error transmitting 'mkzap.com'" '(should have been 174 characters)'
  1646. fi
  1647. fi
  1648. if test -f 'mkzap.bat'
  1649. then
  1650.     echo shar: "will not over-write existing file 'mkzap.bat'"
  1651. else
  1652. cat << \SHAR_EOF > 'mkzap.bat'
  1653. rem compile & link zap for ms-dos
  1654.  
  1655. cl -DLINT_ARGS zap.c
  1656. SHAR_EOF
  1657. if test 56 -ne "`wc -c < 'mkzap.bat'`"
  1658. then
  1659.     echo shar: "error transmitting 'mkzap.bat'" '(should have been 56 characters)'
  1660. fi
  1661. fi
  1662. exit 0
  1663. #    End of shell archive
  1664.  
  1665.